package me.albert.entitylimiter.tasks;

import java.util.ArrayList;
import java.util.List;
import me.albert.entitylimiter.EntityLimiter;
import me.albert.entitylimiter.listeners.ItemListener;
import me.albert.entitylimiter.utils.UtilForFix;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.World;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Item;
import org.bukkit.metadata.FixedMetadataValue;

public class ChunkTask {
    public static void start() {
        if (!EntityLimiter.getInstance().isEnabled()) {
            return;
        }
        Bukkit.getScheduler().runTaskTimerAsynchronously(EntityLimiter.getInstance(), () -> {
            for (World w : Bukkit.getServer().getWorlds()) {
                checkWorld(w);
            }
        }, 0L, 10L);
    }

    private static void checkWorld(final World world) {
        for (final Chunk chunk : world.getLoadedChunks()) {
            checkChunk(chunk);
        }
    }

    private static void checkChunk(final Chunk chunk) {
        try {
            final FileConfiguration config = EntityLimiter.getInstance().getConfig();
            final Entity[] entityList = chunk.getEntities();
            final double tps = UtilForFix.getTps()[UtilForFix.getTps().length - 1];
            final double trigger = config.getDouble("lagging-tps");
            ConfigurationSection entityLimits = config.getConfigurationSection("default-limits");
            final ConfigurationSection lagEntityLimits = config.getConfigurationSection("lagging-limits");
            final ConfigurationSection customGroup = config.getConfigurationSection("custom-groups");
            final ConfigurationSection entityAges = config.getConfigurationSection("entity-ages");
            for (final EntityType type : EntityType.values()) {
                if (entityLimits.getInt(type.toString()) == 0) {
                    entityLimits.set(type.toString(), 100);
                    EntityLimiter.getInstance().saveConfig();
                }
            }
            for (final EntityType type : EntityType.values()) {
                if (lagEntityLimits.getInt(type.toString()) == 0) {
                    lagEntityLimits.set(type.toString(), 100);
                    EntityLimiter.getInstance().saveConfig();
                }
            }
            if (tps < trigger) {
                entityLimits = lagEntityLimits;
            }
            for (Entity entity : entityList) {
                if (entity instanceof Item && entity.getLocation().getBlockY() < 0) {
                    final Item item = (Item) entity;
                    Bukkit.getScheduler().runTask(EntityLimiter.getInstance(), () -> {
                        if (!item.isDead()) {
                            item.remove();
                            ItemListener.sellItem(item.getItemStack(), "void", item);
                        }
                    });
                }
                final EntityType type2 = entity.getType();
                final int age = entityAges.getInt(type2.toString() + ".age");
                if (age > 0) {
                    final boolean removeNamed = entityAges.getBoolean(type2 + ".remove-named");
                    if (entity.getTicksLived() > age) {
                        if (removeNamed) {
                            entity.remove();
                        }
                        if (entity.getCustomName() == null) {
                            entity.remove();
                        }
                    }
                }
                final int limit = entityLimits.getInt(type2.toString());
                final List<Entity> typedEntityList = new ArrayList<Entity>();
                for (final Entity target : entityList) {
                    if (target.getType() == type2 && target.isValid()) {
                        typedEntityList.add(target);
                    }
                }
                removeEntity(typedEntityList, limit);
            }
            for (final String typeName : customGroup.getKeys(false)) {
                final List<String> types = customGroup.getStringList(typeName);
                final List<Entity> groupedEntityList = new ArrayList<Entity>();
                for (final Entity target2 : entityList) {
                    if (!types.contains(target2.getType().toString())) {
                        continue;
                    }
                    final int age2 = entityAges.getInt(typeName + ".age");
                    if (age2 > 0) {
                        final boolean removeNamed2 = entityAges.getBoolean(typeName + ".remove-named");
                        if (target2.getTicksLived() > age2) {
                            if (removeNamed2) {
                                target2.remove();
                            }
                            if (target2.getCustomName() == null) {
                                target2.remove();
                            }
                        }
                    }
                    if (!types.contains(target2.getType().toString()) || !target2.isValid()) {
                        continue;
                    }
                    groupedEntityList.add(target2);
                }
                final int limit = entityLimits.getInt(typeName);
                if (limit > 0) {
                    removeEntity(groupedEntityList, limit);
                }
            }
        } catch (Exception e) {
            if (EntityLimiter.getInstance().getConfig().getBoolean("debug")) {
                e.printStackTrace();
            }
        }
    }

    private static void removeEntity(final List<Entity> entities, final int limit) {
        if (entities.size() > limit) {
            int amount = entities.size() - limit + 1;
            for (final Entity entity : entities) {
                if (--amount <= 0) {
                    break;
                }
                if (entity instanceof Item) {
                    final Item item = (Item) entity;
                    item.setMetadata("itemmerge_removed", new FixedMetadataValue(EntityLimiter.getInstance(), true));
                    Bukkit.getScheduler().runTask(EntityLimiter.getInstance(), () -> {
                        if (!item.isDead()) {
                            item.remove();
                            ItemListener.sellItem(item.getItemStack(), "collide remove", item);
                        }
                    });
                } else {
                    entity.remove();
                }
            }
        }
    }
}
